home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume11 / ephem4.12 / part02 < prev    next >
Encoding:
Text File  |  1990-03-10  |  58.8 KB  |  2,405 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v11i003: ephem, 2 of 7
  3. From: ecd@cs.umn.edu@ncs-med.UUCP (Elwood C. Downey)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 11, Issue 3
  7. Submitted-by: ecd@cs.umn.edu@ncs-med.UUCP (Elwood C. Downey)
  8. Archive-name: ephem4.12/part02
  9.  
  10. # This is the first line of a "shell archive" file.
  11. # This means it contains several files that can be extracted into
  12. # the current directory when run with the sh shell, as follows:
  13. #    sh < this_file_name
  14. # This is file 2.
  15. echo x compiler.c
  16. sed -e 's/^X//' << 'EOFxEOF' > compiler.c
  17. X/* module to compile and execute a c-style arithmetic expression.
  18. X * public entry points are compile_expr() and execute_expr().
  19. X *
  20. X * one reason this is so nice and tight is that all opcodes are the same size
  21. X * (an int) and the tokens the parser returns are directly usable as opcodes,
  22. X * for the most part. constants and variables are compiled as an opcode
  23. X * with an offset into the auxiliary opcode tape, opx.
  24. X */
  25. X
  26. X#include <math.h>
  27. X#include "screen.h"
  28. X
  29. X/* parser tokens and opcodes, as necessary */
  30. X#define    HALT    0    /* good value for HALT since program is inited to 0 */
  31. X/* binary operators (precedences in table, below) */
  32. X#define    ADD    1
  33. X#define    SUB    2
  34. X#define    MULT    3
  35. X#define    DIV    4
  36. X#define    AND    5
  37. X#define    OR    6
  38. X#define    GT    7
  39. X#define    GE    8
  40. X#define    EQ    9
  41. X#define    NE    10
  42. X#define    LT    11
  43. X#define    LE    12
  44. X/* unary op, precedence in NEG_PREC #define, below */
  45. X#define    NEG    13
  46. X/* symantically operands, ie, constants, variables and all functions */
  47. X#define    CONST    14    
  48. X#define    VAR    15
  49. X#define    ABS    16    /* add functions if desired just like this is done */
  50. X/* purely tokens - never get compiled as such */
  51. X#define    LPAREN    255
  52. X#define    RPAREN    254
  53. X#define    ERR    (-1)
  54. X
  55. X/* precedence of each of the binary operators.
  56. X * in case of a tie, compiler associates left-to-right.
  57. X * N.B. each entry's index must correspond to its #define!
  58. X */
  59. Xstatic int precedence[] = {0,5,5,6,6,2,1,4,4,3,3,4,4};
  60. X#define    NEG_PREC    7    /* negation is highest */
  61. X
  62. X/* execute-time operand stack */
  63. X#define    MAX_STACK    16
  64. Xstatic double stack[MAX_STACK], *sp;
  65. X
  66. X/* space for compiled opcodes - the "program".
  67. X * opcodes go in lower 8 bits.
  68. X * when an opcode has an operand (as CONST and VAR) it is really in opx[] and
  69. X *   the index is in the remaining upper bits.
  70. X */
  71. X#define    MAX_PROG 32
  72. Xstatic int program[MAX_PROG], *pc;
  73. X#define    OP_SHIFT    8
  74. X#define    OP_MASK        0xff
  75. X
  76. X/* auxiliary operand info.
  77. X * the operands (all but lower 8 bits) of CONST and VAR are really indeces
  78. X * into this array. thus, no point in making this any longer than you have
  79. X * bits more than 8 in your machine's int to index into it, ie, make
  80. X *    MAX_OPX <= 1 << ((sizeof(int)-1)*8)
  81. X * also, the fld's must refer to ones being flog'd, so not point in more
  82. X * of these then that might be used for plotting and srching combined.
  83. X */
  84. X#define    MAX_OPX    16
  85. Xtypedef union {
  86. X    double opu_f;        /* value when opcode is CONST */
  87. X    int opu_fld;        /* rcfpack() of field when opcode is VAR */
  88. X} OpX;
  89. Xstatic OpX opx[MAX_OPX];
  90. Xstatic int opxidx;
  91. X
  92. X/* these are global just for easy/rapid access */
  93. Xstatic int parens_nest;    /* to check that parens end up nested */
  94. Xstatic char *err_msg;    /* caller provides storage; we point at it with this */
  95. Xstatic char *cexpr, *lcexpr; /* pointers that move along caller's expression */
  96. Xstatic int good_prog;    /* != 0 when program appears to be good */
  97. X
  98. X/* compile the given c-style expression.
  99. X * return 0 and set good_prog if ok,
  100. X * else return -1 and a reason message in errbuf.
  101. X */
  102. Xcompile_expr (ex, errbuf)
  103. Xchar *ex;
  104. Xchar *errbuf;
  105. X{
  106. X    int instr;
  107. X
  108. X    /* init the globals.
  109. X     * also delete any flogs used in the previous program.
  110. X     */
  111. X    cexpr = ex;
  112. X    err_msg = errbuf;
  113. X    pc = program;
  114. X    opxidx = 0;
  115. X    parens_nest = 0;
  116. X    do {
  117. X        instr = *pc++;
  118. X        if ((instr & OP_MASK) == VAR)
  119. X        flog_delete (opx[instr >> OP_SHIFT].opu_fld);
  120. X    } while (instr != HALT);
  121. X
  122. X    pc = program;
  123. X    if (compile(0) == ERR) {
  124. X        sprintf (err_msg + strlen(err_msg), " at \"%.10s\"", lcexpr);
  125. X        good_prog = 0;
  126. X        return (-1);
  127. X    }
  128. X    *pc++ = HALT;
  129. X    good_prog = 1;
  130. X    return (0);
  131. X}
  132. X
  133. X/* execute the expression previously compiled with compile_expr().
  134. X * return 0 with *vp set to the answer if ok, else return -1 with a reason
  135. X * why not message in errbuf.
  136. X */
  137. Xexecute_expr (vp, errbuf)
  138. Xdouble *vp;
  139. Xchar *errbuf;
  140. X{
  141. X    int s;
  142. X
  143. X    err_msg = errbuf;
  144. X    sp = stack + MAX_STACK;    /* grows towards lower addresses */
  145. X    pc = program;
  146. X    s = execute(vp);
  147. X    if (s < 0)
  148. X        good_prog = 0;
  149. X    return (s);
  150. X}
  151. X
  152. X/* this is a way for the outside world to ask whether there is currently a
  153. X * reasonable program compiled and able to execute.
  154. X */
  155. Xprog_isgood()
  156. X{
  157. X    return (good_prog);
  158. X}
  159. X
  160. X/* get and return the opcode corresponding to the next token.
  161. X * leave with lcexpr pointing at the new token, cexpr just after it.
  162. X * also watch for mismatches parens and proper operator/operand alternation.
  163. X */
  164. Xstatic
  165. Xnext_token ()
  166. X{
  167. X    static char toomt[] = "More than %d terms";
  168. X    static char badop[] = "Illegal operator";
  169. X    int tok = ERR;    /* just something illegal */
  170. X    char c;
  171. X
  172. X    while ((c = *cexpr) == ' ')
  173. X        cexpr++;
  174. X    lcexpr = cexpr++;
  175. X
  176. X    /* mainly check for a binary operator */
  177. X    switch (c) {
  178. X    case '\0': --cexpr; tok = HALT; break; /* keep returning HALT */
  179. X    case '+': tok = ADD; break; /* compiler knows when it's really unary */
  180. X    case '-': tok = SUB; break; /* compiler knows when it's really negate */
  181. X    case '*': tok = MULT; break;
  182. X    case '/': tok = DIV; break;
  183. X    case '(': parens_nest++; tok = LPAREN; break;
  184. X    case ')':
  185. X        if (--parens_nest < 0) {
  186. X            sprintf (err_msg, "Too many right parens");
  187. X        return (ERR);
  188. X        } else
  189. X        tok = RPAREN;
  190. X        break;
  191. X    case '|':
  192. X        if (*cexpr == '|') { cexpr++; tok = OR; }
  193. X        else { sprintf (err_msg, badop); return (ERR); }
  194. X        break;
  195. X    case '&':
  196. X        if (*cexpr == '&') { cexpr++; tok = AND; }
  197. X        else { sprintf (err_msg, badop); return (ERR); }
  198. X        break;
  199. X    case '=':
  200. X        if (*cexpr == '=') { cexpr++; tok = EQ; }
  201. X        else { sprintf (err_msg, badop); return (ERR); }
  202. X        break;
  203. X    case '!':
  204. X        if (*cexpr == '=') { cexpr++; tok = NE; }
  205. X        else { sprintf (err_msg, badop); return (ERR); }
  206. X        break;
  207. X    case '<':
  208. X        if (*cexpr == '=') { cexpr++; tok = LE; }
  209. X        else tok = LT;
  210. X        break;
  211. X    case '>':
  212. X        if (*cexpr == '=') { cexpr++; tok = GE; }
  213. X        else tok = GT;
  214. X        break;
  215. X    }
  216. X
  217. X    if (tok != ERR)
  218. X        return (tok);
  219. X
  220. X    /* not op so check for a constant, variable or function */
  221. X    if (isdigit(c) || c == '.') {
  222. X        if (opxidx > MAX_OPX) {
  223. X        sprintf (err_msg, toomt, MAX_OPX);
  224. X        return (ERR);
  225. X        }
  226. X        opx[opxidx].opu_f = atof (lcexpr);
  227. X        tok = CONST | (opxidx++ << OP_SHIFT);
  228. X        skip_double();
  229. X    } else if (isalpha(c)) {
  230. X        /* check list of functions */
  231. X        if (strncmp (lcexpr, "abs", 3) == 0) {
  232. X        cexpr += 2;
  233. X        tok = ABS;
  234. X        } else {
  235. X        /* not a function, so assume it's a variable */
  236. X        int fld;
  237. X        if (opxidx > MAX_OPX) {
  238. X            sprintf (err_msg, toomt, MAX_OPX);
  239. X            return (ERR);
  240. X        }
  241. X        fld = parse_fieldname ();
  242. X        if (fld < 0) {
  243. X            sprintf (err_msg, "Unknown field");
  244. X            return (ERR);
  245. X        } else {
  246. X            if (flog_add (fld) < 0) { /* register with field logger */
  247. X            sprintf (err_msg, "Sorry; too many fields");
  248. X            return (ERR);
  249. X            }
  250. X            opx[opxidx].opu_fld = fld;
  251. X            tok = VAR | (opxidx++ << OP_SHIFT);
  252. X        }
  253. X        }
  254. X    }
  255. X
  256. X    return (tok);
  257. X}
  258. X
  259. X/* move cexpr on past a double.
  260. X * allow sci notation.
  261. X * no need to worry about a leading '-' or '+' but allow them after an 'e'.
  262. X * TODO: this handles all the desired cases, but also admits a bit too much
  263. X *   such as things like 1eee2...3. geeze; to skip a double right you almost
  264. X *   have to go ahead and crack it!
  265. X */
  266. Xstatic
  267. Xskip_double()
  268. X{
  269. X    int sawe = 0;    /* so we can allow '-' or '+' right after an 'e' */
  270. X
  271. X    while (1) {
  272. X        char c = *cexpr;
  273. X        if (isdigit(c) || c=='.' || (sawe && (c=='-' || c=='+'))) {
  274. X        sawe = 0;
  275. X        cexpr++;
  276. X        } else if (c == 'e') {
  277. X        sawe = 1;
  278. X        cexpr++;
  279. X        } else
  280. X        break;
  281. X    }
  282. X}
  283. X
  284. X/* call this whenever you want to dig out the next (sub)expression.
  285. X * keep compiling instructions as long as the operators are higher precedence
  286. X * than prec, then return that "look-ahead" token that wasn't (higher prec).
  287. X * if error, fill in a message in err_msg[] and return ERR.
  288. X */
  289. Xstatic
  290. Xcompile (prec)
  291. Xint prec;
  292. X{
  293. X    int expect_binop = 0;    /* set after we have seen any operand.
  294. X                 * used by SUB so it can tell if it really 
  295. X                 * should be taken to be a NEG instead.
  296. X                 */
  297. X    int tok = next_token ();
  298. X
  299. X        while (1) {
  300. X        int p;
  301. X        if (tok == ERR)
  302. X        return (ERR);
  303. X        if (pc - program >= MAX_PROG) {
  304. X        sprintf (err_msg, "Program is too long");
  305. X        return (ERR);
  306. X        }
  307. X
  308. X        /* check for special things like functions, constants and parens */
  309. X            switch (tok & OP_MASK) {
  310. X            case HALT: return (tok);
  311. X        case ADD:
  312. X        if (expect_binop)
  313. X            break;    /* procede with binary addition */
  314. X        /* just skip a unary positive(?) */
  315. X        tok = next_token();
  316. X        continue;
  317. X        case SUB:
  318. X        if (expect_binop)
  319. X            break;    /* procede with binary subtract */
  320. X        tok = compile (NEG_PREC);
  321. X        *pc++ = NEG;
  322. X        expect_binop = 1;
  323. X        continue;
  324. X            case ABS: /* other funcs would be handled the same too ... */
  325. X        /* eat up the function parenthesized argument */
  326. X        if (next_token() != LPAREN || compile (0) != RPAREN) {
  327. X            sprintf (err_msg, "Function arglist error");
  328. X            return (ERR);
  329. X        }
  330. X        /* then handled same as ... */
  331. X            case CONST: /* handled same as... */
  332. X        case VAR:
  333. X        *pc++ = tok;
  334. X        tok = next_token();
  335. X        expect_binop = 1;
  336. X        continue;
  337. X            case LPAREN:
  338. X        if (compile (0) != RPAREN) {
  339. X            sprintf (err_msg, "Unmatched left paren");
  340. X            return (ERR);
  341. X        }
  342. X        tok = next_token();
  343. X        expect_binop = 1;
  344. X        continue;
  345. X            case RPAREN:
  346. X        return (RPAREN);
  347. X            }
  348. X
  349. X        /* everything else is a binary operator */
  350. X        p = precedence[tok];
  351. X            if (p > prec) {
  352. X                int newtok = compile (p);
  353. X        if (newtok == ERR)
  354. X            return (ERR);
  355. X                *pc++ = tok;
  356. X        expect_binop = 1;
  357. X                tok = newtok;
  358. X            } else
  359. X                return (tok);
  360. X        }
  361. X}
  362. X
  363. X/* "run" the program[] compiled with compile().
  364. X * if ok, return 0 and the final result,
  365. X * else return -1 with a reason why not message in err_msg.
  366. X */
  367. Xstatic
  368. Xexecute(result)
  369. Xdouble *result;
  370. X{
  371. X    int instr; 
  372. X
  373. X    do {
  374. X        instr = *pc++;
  375. X        switch (instr & OP_MASK) {
  376. X        /* put these in numberic order so hopefully even the dumbest
  377. X         * compiler will choose to use a jump table, not a cascade of ifs.
  378. X         */
  379. X        case HALT: break;    /* outer loop will stop us */
  380. X        case ADD:  sp[1] = sp[1] +  sp[0]; sp++; break;
  381. X        case SUB:  sp[1] = sp[1] -  sp[0]; sp++; break;
  382. X        case MULT: sp[1] = sp[1] *  sp[0]; sp++; break;
  383. X        case DIV:  sp[1] = sp[1] /  sp[0]; sp++; break;
  384. X        case AND:  sp[1] = sp[1] && sp[0] ? 1 : 0; sp++; break;
  385. X        case OR:   sp[1] = sp[1] || sp[0] ? 1 : 0; sp++; break;
  386. X        case GT:   sp[1] = sp[1] >  sp[0] ? 1 : 0; sp++; break;
  387. X        case GE:   sp[1] = sp[1] >= sp[0] ? 1 : 0; sp++; break;
  388. X        case EQ:   sp[1] = sp[1] == sp[0] ? 1 : 0; sp++; break;
  389. X        case NE:   sp[1] = sp[1] != sp[0] ? 1 : 0; sp++; break;
  390. X        case LT:   sp[1] = sp[1] <  sp[0] ? 1 : 0; sp++; break;
  391. X        case LE:   sp[1] = sp[1] <= sp[0] ? 1 : 0; sp++; break;
  392. X        case NEG:  *sp = -*sp; break;
  393. X        case CONST: *--sp = opx[instr >> OP_SHIFT].opu_f; break;
  394. X        case VAR:
  395. X        if (flog_get (opx[instr >> OP_SHIFT].opu_fld, --sp) < 0) {
  396. X            sprintf (err_msg, "Bug! VAR field not logged");
  397. X            return (-1);
  398. X        }
  399. X        break;
  400. X        case ABS:  *sp = fabs (*sp); break;
  401. X        default:
  402. X        sprintf (err_msg, "Bug! bad opcode: 0x%x", instr);
  403. X        return (-1);
  404. X        }
  405. X        if (sp < stack) {
  406. X        sprintf (err_msg, "Runtime stack overflow");
  407. X        return (-1);
  408. X        } else if (sp - stack > MAX_STACK) {
  409. X        sprintf (err_msg, "Bug! runtime stack underflow");
  410. X        return (-1);
  411. X        }
  412. X    } while (instr != HALT);
  413. X
  414. X    /* result should now be on top of stack */
  415. X    if (sp != &stack[MAX_STACK - 1]) {
  416. X        sprintf (err_msg, "Bug! stack has %d items",MAX_STACK-(sp-stack));
  417. X        return (-1);
  418. X    }
  419. X    *result = *sp;
  420. X    return (0);
  421. X}
  422. X
  423. Xstatic
  424. Xisdigit(c)
  425. Xchar c;
  426. X{
  427. X    return (c >= '0' && c <= '9');
  428. X}
  429. X
  430. Xstatic
  431. Xisalpha (c)
  432. Xchar c;
  433. X{
  434. X    return ((c >= 'a' && c <= 'z') || (c >=  'A' && c <= 'Z'));
  435. X}
  436. X
  437. X/* starting with lcexpr pointing at a string expected to be a field name,
  438. X * return an rcfpack(r,c,0) of the field else -1 if bad.
  439. X * when return, leave lcexpr alone but move cexpr to just after the name.
  440. X */
  441. Xstatic
  442. Xparse_fieldname ()
  443. X{
  444. X    int r = -1, c = -1;     /* anything illegal */
  445. X    char *fn = lcexpr;    /* likely faster than using the global */
  446. X    char f0, f1;
  447. X    char *dp;
  448. X
  449. X    /* search for first thing not an alpha char.
  450. X     * leave it in f0 and leave dp pointing to it.
  451. X     */
  452. X    dp = fn;
  453. X    while (isalpha(f0 = *dp))
  454. X        dp++;
  455. X
  456. X    /* crack the new field name.
  457. X     * when done trying, leave dp pointing at first char just after it.
  458. X     * set r and c if we recognized it.
  459. X     */
  460. X    if (f0 == '.') {
  461. X        /* planet.column pair.
  462. X         * first crack the planet portion (pointed to by fn): set r.
  463. X         * then the second portion (pointed to by dp+1): set c.
  464. X         */
  465. X        f0 = fn[0];
  466. X        f1 = fn[1];
  467. X        switch (f0) {
  468. X        case 'j':
  469. X                    r = R_JUPITER;
  470. X        break;
  471. X        case 'm':
  472. X        if (f1 == 'a')      r = R_MARS;
  473. X        else if (f1 == 'e') r = R_MERCURY;
  474. X        else if (f1 == 'o') r = R_MOON;
  475. X        break;
  476. X        case 'n':
  477. X                    r = R_NEPTUNE;
  478. X        break;
  479. X        case 'p':
  480. X                    r = R_PLUTO;
  481. X        break;
  482. X        case 's':
  483. X        if (f1 == 'a')      r = R_SATURN;
  484. X        else if (f1 == 'u') r = R_SUN;
  485. X        break;
  486. X        case 'u':
  487. X                    r = R_URANUS;
  488. X        break;
  489. X        case 'x':
  490. X                    r = R_OBJX;
  491. X        break;
  492. X        case 'v':
  493. X                    r = R_VENUS;
  494. X        break;
  495. X        }
  496. X
  497. X        /* now crack the column (stuff after the dp) */
  498. X        dp++;    /* point at good stuff just after the decimal pt */
  499. X        f0 = dp[0];
  500. X        f1 = dp[1];
  501. X        switch (f0) {
  502. X        case 'a':
  503. X        if (f1 == 'l')        c = C_ALT;
  504. X        else if (f1 == 'z')   c = C_AZ;
  505. X        break;
  506. X        case 'd':
  507. X                      c = C_DEC;
  508. X        break;
  509. X        case 'e':
  510. X        if (f1 == 'd')        c = C_EDIST;
  511. X        else if (f1 == 'l')   c = C_ELONG;
  512. X        break;
  513. X        case 'h':
  514. X        if (f1 == 'l') {
  515. X            if (dp[2] == 'a')              c = C_HLAT;
  516. X            else if (dp[2] == 'o')         c = C_HLONG;
  517. X        } else if (f1 == 'r' || f1 == 'u') c = C_TUP;
  518. X        break;
  519. X        case 'j':
  520. X                      c = C_JUPITER;
  521. X        break;
  522. X        case 'm':
  523. X        if (f1 == 'a')        c = C_MARS;
  524. X        else if (f1 == 'e')   c = C_MERCURY;
  525. X        else if (f1 == 'o')   c = C_MOON;
  526. X        break;
  527. X        case 'n':
  528. X                      c = C_NEPTUNE;
  529. X        break;
  530. X        case 'p':
  531. X        if (f1 == 'h')        c = C_PHASE;
  532. X        else if (f1 == 'l')   c = C_PLUTO;
  533. X        break;
  534. X        case 'r':
  535. X        if (f1 == 'a') {
  536. X            if (dp[2] == 'z') c = C_RISEAZ;
  537. X            else           c = C_RA;
  538. X        } else if (f1 == 't') c = C_RISETM;
  539. X        break;
  540. X        case 's':
  541. X        if (f1 == 'a') {
  542. X            if (dp[2] == 'z') c = C_SETAZ;
  543. X            else          c = C_SATURN;
  544. X        } else if (f1 == 'd') c = C_SDIST;
  545. X        else if (f1 == 'i')   c = C_SIZE;
  546. X        else if (f1 == 't')   c = C_SETTM;
  547. X        else if (f1 == 'u')   c = C_SUN;
  548. X        break;
  549. X        case 't':
  550. X        if (f1 == 'a')        c = C_TRANSALT;
  551. X        else if (f1 == 't')   c = C_TRANSTM;
  552. X        break;
  553. X        case 'u':
  554. X                      c = C_URANUS;
  555. X        break;
  556. X        case 'v':
  557. X        if (f1 == 'e')        c = C_VENUS;
  558. X        else if (f1 == 'm')   c = C_MAG;
  559. X        break;
  560. X        }
  561. X
  562. X        /* now skip dp on past the column stuff */
  563. X        while (isalpha(*dp))
  564. X        dp++;
  565. X    } else {
  566. X        /* no decimal point; some field in the top of the screen */
  567. X        f0 = fn[0];
  568. X        f1 = fn[1];
  569. X        switch (f0) {
  570. X        case 'd':
  571. X        if (f1 == 'a')      r = R_DAWN, c = C_DAWNV;
  572. X        else if (f1 == 'u') r = R_DUSK, c = C_DUSKV;
  573. X        break;
  574. X        case 'n':
  575. X        r = R_LON, c = C_LONV;
  576. X        break;
  577. X        }
  578. X    }
  579. X
  580. X    cexpr = dp;
  581. X    if (r <= 0 || c <= 0) return (-1);
  582. X    return (rcfpack (r, c, 0));
  583. X}
  584. EOFxEOF
  585. len=`wc -c < compiler.c`
  586. if expr $len != 15015 > /dev/null
  587. then echo Length of compiler.c is $len but it should be 15015.
  588. fi
  589. echo x eq_ecl.c
  590. sed -e 's/^X//' << 'EOFxEOF' > eq_ecl.c
  591. X#include <stdio.h>
  592. X#include <math.h>
  593. X#include "astro.h"
  594. X
  595. X#define    EQtoECL    1
  596. X#define    ECLtoEQ    (-1)
  597. X
  598. X/* given the modified Julian date, mjd, and an equitorial ra and dec, each in
  599. X * radians, find the corresponding geocentric ecliptic latitude, *lat, and
  600. X * longititude, *lng, also each in radians.
  601. X * correction for the effect on the angle of the obliquity due to nutation is
  602. X * included.
  603. X */
  604. Xeq_ecl (mjd, ra, dec, lat, lng)
  605. Xdouble mjd, ra, dec;
  606. Xdouble *lat, *lng;
  607. X{
  608. X    ecleq_aux (EQtoECL, mjd, ra, dec, lng, lat);
  609. X}
  610. X
  611. X/* given the modified Julian date, mjd, and a geocentric ecliptic latitude,
  612. X * *lat, and longititude, *lng, each in radians, find the corresponding
  613. X * equitorial ra and dec, also each in radians.
  614. X * correction for the effect on the angle of the obliquity due to nutation is
  615. X * included.
  616. X */
  617. Xecl_eq (mjd, lat, lng, ra, dec)
  618. Xdouble mjd, lat, lng;
  619. Xdouble *ra, *dec;
  620. X{
  621. X    ecleq_aux (ECLtoEQ, mjd, lng, lat, ra, dec);
  622. X}
  623. X
  624. Xstatic
  625. Xecleq_aux (sw, mjd, x, y, p, q)
  626. Xint sw;            /* +1 for eq to ecliptic, -1 for vv. */
  627. Xdouble mjd, x, y;    /* sw==1: x==ra, y==dec.  sw==-1: x==lng, y==lat. */
  628. Xdouble *p, *q;        /* sw==1: p==lng, q==lat. sw==-1: p==ra, q==dec. */
  629. X{
  630. X    static double lastmjd;        /* last mjd calculated */
  631. X    static double seps, ceps;    /* sin and cos of mean obliquity */
  632. X    double sx, cx, sy, cy, ty;
  633. X
  634. X    if (mjd != lastmjd) {
  635. X        double eps;
  636. X        double deps, dpsi;
  637. X        obliquity (mjd, &eps);        /* mean obliquity for date */
  638. X        nutation (mjd, &deps, &dpsi);
  639. X        eps += deps;
  640. X            seps = sin(eps);
  641. X        ceps = cos(eps);
  642. X        lastmjd = mjd;
  643. X    }
  644. X
  645. X    sy = sin(y);
  646. X    cy = cos(y);                /* always non-negative */
  647. X        if (fabs(cy)<1e-20) cy = 1e-20;        /* insure > 0 */
  648. X        ty = sy/cy;
  649. X    cx = cos(x);
  650. X    sx = sin(x);
  651. X        *q = asin((sy*ceps)-(cy*seps*sx*sw));
  652. X        *p = atan(((sx*ceps)+(ty*seps*sw))/cx);
  653. X        if (cx<0) *p += PI;        /* account for atan quad ambiguity */
  654. X    range (p, 2*PI);
  655. X}
  656. EOFxEOF
  657. len=`wc -c < eq_ecl.c`
  658. if expr $len != 1891 > /dev/null
  659. then echo Length of eq_ecl.c is $len but it should be 1891.
  660. fi
  661. echo x flog.c
  662. sed -e 's/^X//' << 'EOFxEOF' > flog.c
  663. X/* this is a simple little package to manage the saving and retrieving of
  664. X * field values, which we call field logging or "flogs". a flog consists of a
  665. X * field location, ala rcfpack(), and its value as a double. you can reset the
  666. X * list of flogs, add to and remove from the list of registered fields and log
  667. X * a field if it has been registered.
  668. X *
  669. X * this is used by the plotting and searching facilities of ephem to maintain
  670. X * the values of the fields that are being plotted or used in search
  671. X * expressions.
  672. X *
  673. X * a field can be in use for more than one
  674. X * thing at a time (eg, all the X plot values may the same time field, or
  675. X * searching and plotting might be on at one time using the same field) so
  676. X * we consider the field to be in use as long a usage count is > 0.
  677. X */
  678. X
  679. X#include "screen.h"
  680. X
  681. X#define    NFLOGS    32
  682. X
  683. Xtypedef struct {
  684. X    int fl_usagecnt;    /* number of "users" logging to this field */
  685. X    int fl_fld;        /* an rcfpack(r,c,0) */
  686. X    double fl_val;
  687. X} FLog;
  688. X
  689. Xstatic FLog flog[NFLOGS];
  690. X
  691. X/* add fld to the list. if already there, just increment usage count.
  692. X * return 0 if ok, else -1 if no more room.
  693. X */
  694. Xflog_add (fld)
  695. Xint fld;
  696. X{
  697. X    FLog *flp, *unusedflp = 0;
  698. X
  699. X    /* scan for fld already in list, or find an unused one along the way */
  700. X    for (flp = &flog[NFLOGS]; --flp >= flog; ) {
  701. X        if (flp->fl_usagecnt > 0) {
  702. X        if (flp->fl_fld == fld) {
  703. X            flp->fl_usagecnt++;
  704. X            return (0);
  705. X        }
  706. X        } else
  707. X        unusedflp = flp;
  708. X    }
  709. X    if (unusedflp) {
  710. X        unusedflp->fl_fld = fld;
  711. X        unusedflp->fl_usagecnt = 1;
  712. X        return (0);
  713. X    }
  714. X    return (-1);
  715. X}
  716. X
  717. X/* decrement usage count for flog for fld. if goes to 0 take it out of list.
  718. X * ok if not in list i guess...
  719. X */
  720. Xflog_delete (fld)
  721. Xint fld;
  722. X{
  723. X    FLog *flp;
  724. X
  725. X    for (flp = &flog[NFLOGS]; --flp >= flog; )
  726. X        if (flp->fl_fld == fld && flp->fl_usagecnt > 0) {
  727. X        if (--flp->fl_usagecnt <= 0) {
  728. X            flp->fl_usagecnt = 0;
  729. X        }
  730. X        break;
  731. X        }
  732. X}
  733. X
  734. X/* if plotting or searching is active then
  735. X * if rcfpack(r,c,0) is in the fld list, set its value to val.
  736. X * return 0 if ok, else -1 if not in list.
  737. X */
  738. Xflog_log (r, c, val)
  739. Xint r, c;
  740. Xdouble val;
  741. X{
  742. X    if (plot_ison() || srch_ison()) {
  743. X        FLog *flp;
  744. X        int fld = rcfpack (r, c, 0);
  745. X        for (flp = &flog[NFLOGS]; --flp >= flog; )
  746. X        if (flp->fl_fld == fld && flp->fl_usagecnt > 0) {
  747. X            flp->fl_val = val;
  748. X            return(0);
  749. X        }
  750. X        return (-1);
  751. X    } else
  752. X        return (0);
  753. X}
  754. X
  755. X/* search for fld in list. if find it return its value.
  756. X * return 0 if found it, else -1 if not in list.
  757. X */
  758. Xflog_get (fld, vp)
  759. Xint fld;
  760. Xdouble *vp;
  761. X{
  762. X    FLog *flp;
  763. X
  764. X    for (flp = &flog[NFLOGS]; --flp >= flog; )
  765. X        if (flp->fl_fld == fld && flp->fl_usagecnt > 0) {
  766. X        *vp = flp->fl_val;
  767. X        return (0);
  768. X        }
  769. X    return (-1);
  770. X}
  771. EOFxEOF
  772. len=`wc -c < flog.c`
  773. if expr $len != 2680 > /dev/null
  774. then echo Length of flog.c is $len but it should be 2680.
  775. fi
  776. echo x formats.c
  777. sed -e 's/^X//' << 'EOFxEOF' > formats.c
  778. X/* basic formating routines.
  779. X * all the screen oriented printing should go through here.
  780. X */
  781. X
  782. X#include <stdio.h>
  783. X#include <math.h>
  784. X#include "astro.h"
  785. X#include "screen.h"
  786. X
  787. Xextern char *strcpy();
  788. X
  789. X/* suppress screen io if this is true, but always flog stuff.
  790. X */
  791. Xstatic int f_scrnoff;
  792. Xf_on ()
  793. X{
  794. X    f_scrnoff = 0;
  795. X}
  796. Xf_off ()
  797. X{
  798. X    f_scrnoff = 1;
  799. X}
  800. X
  801. X/* draw n blanks at the given cursor position.  */
  802. Xf_blanks (r, c, n)
  803. Xint r, c, n;
  804. X{
  805. X    if (f_scrnoff)
  806. X        return;
  807. X    c_pos (r, c);
  808. X    while (--n >= 0)
  809. X        putchar (' ');
  810. X}
  811. X
  812. X/* print the given value, v, in "sexadecimal" format at [r,c]
  813. X * ie, in the form A:m.P, where A is a digits wide, P is p digits.
  814. X * if p == 0, then no decimal point either.
  815. X */
  816. Xf_sexad (r, c, a, p, mod, v)
  817. Xint r, c;
  818. Xint a, p;    /* left space, min precision */
  819. Xint mod;    /* don't let whole portion get this big */
  820. Xdouble v;
  821. X{
  822. X    char astr[32], str[32];
  823. X    long dec;
  824. X    double frac;
  825. X    int visneg;
  826. X
  827. X    (void) flog_log (r, c, v);
  828. X
  829. X    if (f_scrnoff)
  830. X        return;
  831. X
  832. X    if (v >= 0.0)
  833. X        visneg = 0;
  834. X    else {
  835. X        if (v <= -0.5/60.0*pow(10.0,-1.0*p)) {
  836. X        v = -v;
  837. X        visneg = 1;
  838. X        } else {
  839. X        /* don't show as negative if less than the precision showing */
  840. X        v = 0.0;
  841. X        visneg = 0;
  842. X        }
  843. X    }
  844. X
  845. X    dec = v;
  846. X    frac = (v - dec)*60.0;
  847. X    sprintf (str, "59.%.*s5", p, "999999999");
  848. X    if (frac >= atof (str)) {
  849. X        dec += 1;
  850. X        frac = 0.0;
  851. X    }
  852. X    dec %= mod;
  853. X    if (dec == 0 && visneg)
  854. X        strcpy (str, "-0");
  855. X    else
  856. X        sprintf (str, "%ld", visneg ? -dec : dec);
  857. X
  858. X    /* would just do this if Turbo-C 2.0 %?.0f" worked:
  859. X     * sprintf (astr, "%*s:%0*.*f", a, str, p == 0 ? 2 : p+3, p, frac);
  860. X     */
  861. X    if (p == 0)
  862. X        sprintf (astr, "%*s:%02d", a, str, (int)(frac+0.5));
  863. X    else
  864. X        sprintf (astr, "%*s:%0*.*f", a, str, p+3, p, frac);
  865. X    f_string (r, c, astr);
  866. X}
  867. X
  868. X/* print the given value, t, in sexagesimal format at [r,c]
  869. X * ie, in the form T:mm:ss, where T is nd digits wide.
  870. X * N.B. we assume nd >= 2.
  871. X */
  872. Xf_sexag (r, c, nd, t)
  873. Xint r, c, nd;
  874. Xdouble t;
  875. X{
  876. X    char tstr[32];
  877. X    int h, m, s;
  878. X    int tisneg;
  879. X    
  880. X    (void) flog_log (r, c, t);
  881. X    if (f_scrnoff)
  882. X        return;
  883. X    dec_sex (t, &h, &m, &s, &tisneg);
  884. X    if (h == 0 && tisneg)
  885. X        sprintf (tstr, "%*s-0:%02d:%02d", nd-2, "", m, s);
  886. X    else
  887. X        sprintf (tstr, "%*d:%02d:%02d", nd, tisneg ? -h : h, m, s);
  888. X    f_string (r, c, tstr);
  889. X}
  890. X
  891. X/* print angle ra, in radians, in ra hours as hh:mm.m at [r,c]
  892. X * N.B. we assume ra is >= 0.
  893. X */
  894. Xf_ra (r, c, ra)
  895. Xint r, c;
  896. Xdouble ra;
  897. X{
  898. X    f_sexad (r, c, 2, 1, 24, radhr(ra));
  899. X}
  900. X
  901. X/* print time, t, as hh:mm:ss */
  902. Xf_time (r, c, t)
  903. Xint r, c;
  904. Xdouble t;
  905. X{
  906. X    f_sexag (r, c, 2, t);
  907. X}
  908. X
  909. X/* print time, t, as +/-hh:mm:ss (don't show leading +) */
  910. Xf_signtime (r, c, t)
  911. Xint r, c;
  912. Xdouble t;
  913. X{
  914. X    f_sexag (r, c, 3, t);
  915. X}
  916. X
  917. X/* print time, t, as hh:mm */
  918. Xf_mtime (r, c, t)
  919. Xint r, c;
  920. Xdouble t;
  921. X{
  922. X    f_sexad (r, c, 2, 0, 24, t);
  923. X}
  924. X
  925. X/* print angle, a, in rads, as degress at [r,c] in form ddd:mm */
  926. Xf_angle(r, c, a)
  927. Xint r, c;
  928. Xdouble a;
  929. X{
  930. X    f_sexad (r, c, 3, 0, 360, raddeg(a));
  931. X}
  932. X
  933. X/* print angle, a, in rads, as degress at [r,c] in form dddd:mm:ss */
  934. Xf_gangle(r, c, a)
  935. Xint r, c;
  936. Xdouble a;
  937. X{
  938. X    f_sexag (r, c, 4, raddeg(a));
  939. X}
  940. X
  941. X/* print the given modified Julian date, jd, as the starting date at [r,c]
  942. X * in the form mm/dd/yyyy.
  943. X */
  944. Xf_date (r, c, jd)
  945. Xint r, c;
  946. Xdouble jd;
  947. X{
  948. X    char dstr[32];
  949. X    int m, y;
  950. X    double d, tmp;
  951. X
  952. X    /* shadow to the plot subsystem as years. */
  953. X    mjd_year (jd, &tmp);
  954. X    (void) flog_log (r, c, tmp);
  955. X    if (f_scrnoff)
  956. X        return;
  957. X
  958. X    mjd_cal (jd, &m, &d, &y);
  959. X
  960. X    sprintf (dstr, "%2d/%02d/%04d", m, (int)(d), y);
  961. X    f_string (r, c, dstr);
  962. X}
  963. X
  964. Xf_char (row, col, c)
  965. Xint row, col;
  966. Xchar c;
  967. X{
  968. X    if (f_scrnoff)
  969. X        return;
  970. X    c_pos (row, col);
  971. X    putchar (c);
  972. X}
  973. X
  974. Xf_string (r, c, s)
  975. Xint r, c;
  976. Xchar *s;
  977. X{
  978. X    if (f_scrnoff)
  979. X        return;
  980. X    c_pos (r, c);
  981. X    fputs (s, stdout);
  982. X}
  983. X
  984. Xf_double (r, c, fmt, f)
  985. Xint r, c;
  986. Xchar *fmt;
  987. Xdouble f;
  988. X{
  989. X    char str[80];
  990. X    (void) flog_log (r, c, f);
  991. X    sprintf (str, fmt, f);
  992. X    f_string (r, c, str);
  993. X}
  994. X
  995. X/* print prompt line */
  996. Xf_prompt (p)
  997. Xchar *p;
  998. X{
  999. X    c_pos (R_PROMPT, C_PROMPT);
  1000. X    c_eol ();
  1001. X    c_pos (R_PROMPT, C_PROMPT);
  1002. X    fputs (p, stdout);
  1003. X}
  1004. X
  1005. X/* clear from [r,c] to end of line, if we are drawing now. */
  1006. Xf_eol (r, c)
  1007. Xint r, c;
  1008. X{
  1009. X    if (!f_scrnoff) {
  1010. X        c_pos (r, c);
  1011. X        c_eol();
  1012. X    }
  1013. X}
  1014. X
  1015. X/* print a message and wait for op to hit any key */
  1016. Xf_msg (m)
  1017. Xchar *m;
  1018. X{
  1019. X    f_prompt (m);
  1020. X    (void) read_char();
  1021. X}
  1022. X
  1023. X/* crack a line of the form X?X?X into its components,
  1024. X *   where X is an integer and ? can be any character except '0-9' or '-',
  1025. X *   such as ':' or '/'.
  1026. X * only change those fields that are specified:
  1027. X *   eg:  ::10    only changes *s
  1028. X *        10    only changes *d
  1029. X *        10:0  changes *d and *m
  1030. X * if see '-' anywhere, first non-zero component will be made negative.
  1031. X */
  1032. Xf_sscansex (bp, d, m, s)
  1033. Xchar *bp;
  1034. Xint *d, *m, *s;
  1035. X{
  1036. X    char c;
  1037. X    int *p = d;
  1038. X    int *nonzp = 0;
  1039. X    int sawneg = 0;
  1040. X    int innum = 0;
  1041. X
  1042. X    while (c = *bp++)
  1043. X        if (c >= '0' && c <= '9') {
  1044. X        if (!innum) {
  1045. X            *p = 0;
  1046. X            innum = 1;
  1047. X        }
  1048. X        *p = *p*10 + (c - '0');
  1049. X        if (*p && !nonzp)
  1050. X            nonzp = p;
  1051. X        } else if (c == '-') {
  1052. X        sawneg = 1;
  1053. X        } else if (c != ' ') {
  1054. X        /* advance to next component */
  1055. X        p = (p == d) ? m : s;
  1056. X        innum = 0;
  1057. X        }
  1058. X
  1059. X    if (sawneg && nonzp)
  1060. X        *nonzp = -*nonzp;
  1061. X}
  1062. X
  1063. X/* crack a floating date string, bp, of the form m/d/y, where d may be a
  1064. X *   floating point number, into its components.
  1065. X * leave any component unspecified unchanged.
  1066. X * actually, the slashes may be anything but digits or a decimal point.
  1067. X * this is functionally the same as f_sscansex() exept we allow for
  1068. X *   the day portion to be real, and we don't handle negative numbers.
  1069. X *   maybe someday we could make a combined one and use it everywhere.
  1070. X */
  1071. Xf_sscandate (bp, m, d, y)
  1072. Xchar *bp;
  1073. Xint *m, *y;
  1074. Xdouble *d;
  1075. X{
  1076. X    char *bp0, c;
  1077. X
  1078. X    bp0 = bp;
  1079. X    while ((c = *bp++) && (c >= '0' && c <= '9'))
  1080. X        continue;
  1081. X    if (bp > bp0+1)
  1082. X        *m = atoi (bp0);
  1083. X    if (c == '\0')
  1084. X        return;
  1085. X    bp0 = bp;
  1086. X    while ((c = *bp++) && (c >= '0' && c <= '9' || c == '.'))
  1087. X        continue;
  1088. X    if (bp > bp0+1)
  1089. X        *d = atof (bp0);
  1090. X    if (c == '\0')
  1091. X        return;
  1092. X    bp0 = bp;
  1093. X    while (c = *bp++)
  1094. X        continue;
  1095. X    if (bp > bp0+1)
  1096. X        *y = atoi (bp0);
  1097. X}
  1098. X
  1099. X/* just like dec_sex() but makes the first non-zero element negative if
  1100. X * x is negative (instead of returning a sign flag).
  1101. X */
  1102. Xf_dec_sexsign (x, h, m, s)
  1103. Xdouble x;
  1104. Xint *h, *m, *s;
  1105. X{
  1106. X    int n;
  1107. X    dec_sex (x, h, m, s, &n);
  1108. X    if (n) {
  1109. X        if (*h)
  1110. X        *h = -*h;
  1111. X        else if (*m)
  1112. X        *m = -*m;
  1113. X        else
  1114. X        *s = -*s;
  1115. X    }
  1116. X}
  1117. X
  1118. X/* return 1 if bp looks like a decimal year; else 0.
  1119. X * any number greater than 12 is assumed to be a year, or any string
  1120. X * with exactly one decimal point, an optional minus sign, and nothing
  1121. X * else but digits.
  1122. X */
  1123. Xdecimal_year (bp)
  1124. Xchar *bp;
  1125. X{
  1126. X    char c;
  1127. X    int ndig = 0, ndp = 0, nneg = 0, nchar = 0;
  1128. X    int n = atoi(bp);
  1129. X
  1130. X    while (c = *bp++) {
  1131. X        nchar++;
  1132. X        if (c >= '0' && c <= '9')
  1133. X        ndig++;
  1134. X        else if (c == '.')
  1135. X        ndp++;
  1136. X        else if (c == '-')
  1137. X        nneg++;
  1138. X    }
  1139. X
  1140. X    return (n > 12 || (ndp == 1 && nneg <= 1 && nchar == ndig+ndp+nneg));
  1141. X}
  1142. EOFxEOF
  1143. len=`wc -c < formats.c`
  1144. if expr $len != 6850 > /dev/null
  1145. then echo Length of formats.c is $len but it should be 6850.
  1146. fi
  1147. echo x io.c
  1148. sed -e 's/^X//' << 'EOFxEOF' > io.c
  1149. X/* this file (in principle) contains all the device-dependent code for
  1150. X * handling screen movement and reading the keyboard. public routines are:
  1151. X *   c_pos(r,c), c_erase(), c_eol();
  1152. X *   chk_char(), read_char(), read_line (buf, max); and
  1153. X *   byetty().
  1154. X * N.B. we assume output may be performed by printf(), putchar() and
  1155. X *   fputs(stdout). since these are buffered we flush first in read_char().
  1156. X */
  1157. X
  1158. X/* explanation of various conditional #define options:
  1159. X * UNIX: uses termcap for screen management.
  1160. X *   USE_NDELAY: does non-blocking tty reads with fcntl(O_NDELAY); otherwise
  1161. X *     this is done with ioctl(..,FIONREAD..). Use which ever works on your
  1162. X *     system.
  1163. X * TURBO_C: compiles for Turbo C 2.0. I'm told it works for Lattice and
  1164. X *     Microsoft too.
  1165. X *   USE_ANSISYS: default PC cursor control uses direct BIOS calls (thanks to
  1166. X *     Mr. Doug McDonald). If your PC does not work with this, however, add
  1167. X *     "device ANSI.SYS" to your config.sys file and build ephem with
  1168. X *     USE_ANSISYS.
  1169. X */
  1170. X
  1171. X#define    UNIX
  1172. X/* #define USE_NDELAY */
  1173. X/* #define TURBO_C */
  1174. X/* #define USE_ANSISYS */
  1175. X
  1176. X#include <stdio.h>
  1177. X#include "screen.h"
  1178. X
  1179. X#ifdef UNIX
  1180. X#include <sgtty.h>
  1181. X#include <signal.h>
  1182. X#ifdef USE_NDELAY
  1183. X#include <fcntl.h>
  1184. X#endif
  1185. X
  1186. Xextern char *tgoto();
  1187. Xstatic char *cm, *ce, *cl, *kl, *kr, *ku, *kd; /* curses sequences */
  1188. Xstatic int tloaded;
  1189. Xstatic int ttysetup;
  1190. Xstatic struct sgttyb orig_sgtty;
  1191. X
  1192. X/* move cursor to row, col, 1-based.
  1193. X * we assume this also moves a visible cursor to this location.
  1194. X */
  1195. Xc_pos (r, c)
  1196. Xint r, c;
  1197. X{
  1198. X    if (!tloaded) tload();
  1199. X    fputs (tgoto (cm, c-1, r-1), stdout);
  1200. X}
  1201. X
  1202. X/* erase entire screen. */
  1203. Xc_erase()
  1204. X{
  1205. X    if (!tloaded) tload();
  1206. X    fputs (cl, stdout);
  1207. X}
  1208. X
  1209. X/* erase to end of line */
  1210. Xc_eol()
  1211. X{
  1212. X    if (!tloaded) tload();
  1213. X    fputs (ce, stdout);
  1214. X}
  1215. X
  1216. X#ifdef USE_NDELAY
  1217. Xstatic char sav_char;    /* one character read-ahead for chk_char() */
  1218. X#endif
  1219. X
  1220. X/* return 0 if there is a char that may be read without blocking, else -1 */
  1221. Xchk_char()
  1222. X{
  1223. X#ifdef USE_NDELAY
  1224. X    if (!ttysetup) setuptty();
  1225. X    if (sav_char)
  1226. X        return (0);
  1227. X    fcntl (0, F_SETFL, O_NDELAY);    /* non-blocking read. FNDELAY on BSD */
  1228. X    if (read (0, &sav_char, 1) != 1)
  1229. X        sav_char = 0;
  1230. X    return (sav_char ? 0 : -1);
  1231. X#else
  1232. X    long n;
  1233. X    if (!ttysetup) setuptty();
  1234. X    ioctl (0, FIONREAD, &n);
  1235. X    return (n > 0 ? 0 : -1);
  1236. X#endif
  1237. X}
  1238. X
  1239. X/* read the next char, blocking if necessary, and return it. don't echo.
  1240. X * map the arrow keys if we can too into hjkl
  1241. X */
  1242. Xread_char()
  1243. X{
  1244. X    char c;
  1245. X    if (!ttysetup) setuptty();
  1246. X    fflush (stdout);
  1247. X#ifdef USE_NDELAY
  1248. X    fcntl (0, F_SETFL, 0);    /* blocking read */
  1249. X    if (sav_char) {
  1250. X        c = sav_char;
  1251. X        sav_char = 0;
  1252. X    } else
  1253. X#endif
  1254. X        read (0, &c, 1);
  1255. X    c = chk_arrow (c & 0177); /* just ASCII, please */
  1256. X    return (c);
  1257. X}
  1258. X
  1259. X/* used to time out of a read */
  1260. Xstatic got_alrm;
  1261. Xstatic
  1262. Xon_alrm()
  1263. X{
  1264. X    got_alrm = 1;
  1265. X}
  1266. X
  1267. X/* see if c is the first of any of the curses arrow key sequences.
  1268. X * if it is, read the rest of the sequence, and return the hjkl code
  1269. X * that corresponds.
  1270. X * if no match, just return c.
  1271. X */
  1272. Xstatic 
  1273. Xchk_arrow (c)
  1274. Xregister char c;
  1275. X{
  1276. X    register char *seq;
  1277. X
  1278. X    if (c == *(seq = kl) || c == *(seq = kd) || c == *(seq = ku)
  1279. X                         || c == *(seq = kr)) {
  1280. X        char seqa[32]; /* maximum arrow escape sequence ever expected */
  1281. X        unsigned l = strlen(seq);
  1282. X        seqa[0] = c;
  1283. X        if (l > 1) {
  1284. X        extern unsigned alarm();
  1285. X        /* cautiously read rest of arrow sequence */
  1286. X        got_alrm = 0;
  1287. X        signal (SIGALRM, on_alrm);
  1288. X        alarm(2);
  1289. X        read (0, seqa+1, l-1);
  1290. X        alarm(0);
  1291. X        if (got_alrm)
  1292. X            return (c);
  1293. X        }
  1294. X        seqa[l] = '\0';
  1295. X        if (strcmp (seqa, kl) == 0)
  1296. X        return ('h');
  1297. X        if (strcmp (seqa, kd) == 0)
  1298. X        return ('j');
  1299. X        if (strcmp (seqa, ku) == 0)
  1300. X        return ('k');
  1301. X        if (strcmp (seqa, kr) == 0)
  1302. X        return ('l');
  1303. X    }
  1304. X    return (c);
  1305. X}
  1306. X
  1307. X/* do whatever might be necessary to get the screen and/or tty back into shape.
  1308. X */
  1309. Xbyetty()
  1310. X{
  1311. X    ioctl (0, TIOCSETP, &orig_sgtty);
  1312. X#ifdef USE_NDELAY
  1313. X    fcntl (0, F_SETFL, 0);    /* be sure to go back to blocking read */
  1314. X#endif
  1315. X}
  1316. X
  1317. Xstatic 
  1318. Xtload()
  1319. X{
  1320. X    extern char *getenv(), *tgetstr();
  1321. X    extern char *UP, *BC;
  1322. X    char *egetstr();
  1323. X    static char tbuf[512];
  1324. X    char rawtbuf[1024];
  1325. X    char *tp;
  1326. X    char *ptr;
  1327. X
  1328. X    if (!(tp = getenv ("TERM"))) {
  1329. X        printf ("Must have addressable cursor\n");
  1330. X        exit(1);
  1331. X    }
  1332. X
  1333. X    if (!ttysetup) setuptty();
  1334. X    if (tgetent (rawtbuf, tp) != 1) {
  1335. X        printf ("Can't find termcap for %s\n", tp);
  1336. X        exit (1);
  1337. X    }
  1338. X    ptr = tbuf;
  1339. X    ku = egetstr ("ku", &ptr);
  1340. X    kd = egetstr ("kd", &ptr);
  1341. X    kl = egetstr ("kl", &ptr);
  1342. X    kr = egetstr ("kr", &ptr);
  1343. X    cm = egetstr ("cm", &ptr);
  1344. X    ce = egetstr ("ce", &ptr);
  1345. X    cl = egetstr ("cl", &ptr);
  1346. X    UP = egetstr ("up", &ptr);
  1347. X    if (!tgetflag ("bs"))
  1348. X        BC = egetstr ("bc", &ptr);
  1349. X    tloaded = 1;
  1350. X}
  1351. X
  1352. X/* like tgetstr() but discard curses delay codes, for now anyways */
  1353. Xstatic char *
  1354. Xegetstr (name, sptr)
  1355. Xchar *name;
  1356. Xchar **sptr;
  1357. X{
  1358. X    extern char *tgetstr();
  1359. X    register char c, *s;
  1360. X
  1361. X    s = tgetstr (name, sptr);
  1362. X    while (((c = *s) >= '0' && c <= '9') || c == '*')
  1363. X        s += 1;
  1364. X    return (s);
  1365. X}
  1366. X
  1367. X/* set up tty for char-by-char read, non-blocking  */
  1368. Xstatic
  1369. Xsetuptty()
  1370. X{
  1371. X    struct sgttyb sg;
  1372. X
  1373. X    ioctl (0, TIOCGETP, &orig_sgtty);
  1374. X    sg = orig_sgtty;
  1375. X    sg.sg_flags &= ~ECHO;    /* do our own echoing */
  1376. X    sg.sg_flags &= ~CRMOD;    /* leave CR and LF unchanged */
  1377. X    sg.sg_flags |= XTABS;    /* no tabs with termcap */
  1378. X    sg.sg_flags |= CBREAK;    /* wake up on each char but can still kill */
  1379. X    ioctl (0, TIOCSETP, &sg);
  1380. X    ttysetup = 1;
  1381. X}
  1382. X#endif
  1383. X
  1384. X#ifdef TURBO_C
  1385. X#ifdef USE_ANSISYS
  1386. X#define    ESC    '\033'
  1387. X/* position cursor.
  1388. X * (ANSI: ESC [ r ; c f) (r/c are numbers given in ASCII digits)
  1389. X */
  1390. Xc_pos (r, c)
  1391. Xint r, c;
  1392. X{
  1393. X    printf ("%c[%d;%df", ESC, r, c);
  1394. X}
  1395. X
  1396. X/* erase entire screen. (ANSI: ESC [ 2 J) */
  1397. Xc_erase()
  1398. X{
  1399. X    printf ("%c[2J", ESC);
  1400. X}
  1401. X
  1402. X/* erase to end of line. (ANSI: ESC [ K) */
  1403. Xc_eol()
  1404. X{
  1405. X    printf ("%c[K", ESC);
  1406. X}
  1407. X#else
  1408. X#include <dos.h>   
  1409. Xunion REGS rg;
  1410. X
  1411. X/* position cursor.
  1412. X */
  1413. Xc_pos (r, c)
  1414. Xint r, c;
  1415. X{
  1416. X        rg.h.ah = 2;
  1417. X        rg.h.bh = 0;
  1418. X        rg.h.dh = r-1;
  1419. X        rg.h.dl = c-1;
  1420. X        int86(16,&rg,&rg);
  1421. X}
  1422. X
  1423. X/* erase entire screen.  */
  1424. Xc_erase()
  1425. X{
  1426. X        int cur_cursor, i;
  1427. X        rg.h.ah = 3;
  1428. X        rg.h.bh = 0;
  1429. X        int86(16,&rg,&rg);
  1430. X        cur_cursor = rg.x.dx;
  1431. X        for(i = 0; i < 25; i++){
  1432. X            c_pos(i+1,1);
  1433. X            rg.h.ah = 10;
  1434. X            rg.h.bh = 0;
  1435. X            rg.h.al = 32;
  1436. X            rg.x.cx = 80;
  1437. X            int86(16,&rg,&rg);
  1438. X        }
  1439. X        rg.h.ah = 2;
  1440. X        rg.h.bh = 0;
  1441. X        rg.x.dx = cur_cursor;
  1442. X        int86(16,&rg,&rg);
  1443. X        
  1444. X}
  1445. X
  1446. X/* erase to end of line.*/
  1447. Xc_eol()
  1448. X{
  1449. X        int cur_cursor, i;
  1450. X        rg.h.ah = 3;
  1451. X        rg.h.bh = 0;
  1452. X        int86(16,&rg,&rg);
  1453. X        cur_cursor = rg.x.dx;
  1454. X        rg.h.ah = 10;
  1455. X        rg.h.bh = 0;
  1456. X        rg.h.al = 32;
  1457. X        rg.x.cx = 80 - rg.h.dl;
  1458. X        int86(16,&rg,&rg);
  1459. X        rg.h.ah = 2;
  1460. X        rg.h.bh = 0;
  1461. X        rg.x.dx = cur_cursor;
  1462. X        int86(16,&rg,&rg);
  1463. X
  1464. X}
  1465. X#endif
  1466. X
  1467. X/* return 0 if there is a char that may be read without blocking, else -1 */
  1468. Xchk_char()
  1469. X{
  1470. X    return (kbhit() == 0 ? -1 : 0);
  1471. X}
  1472. X
  1473. X/* read the next char, blocking if necessary, and return it. don't echo.
  1474. X * map the arrow keys if we can too into hjkl
  1475. X */
  1476. Xread_char()
  1477. X{
  1478. X    int c;
  1479. X    fflush (stdout);
  1480. X    c = getch();
  1481. X    if (c == 0) {
  1482. X        /* get scan code; convert to direction hjkl if possible */
  1483. X        c = getch();
  1484. X        switch (c) {
  1485. X        case 0x4b: c = 'h'; break;
  1486. X        case 0x50: c = 'j'; break;
  1487. X        case 0x48: c = 'k'; break;
  1488. X        case 0x4d: c = 'l'; break;
  1489. X        }
  1490. X    }
  1491. X    return (c);
  1492. X}
  1493. X
  1494. X/* do whatever might be necessary to get the screen and/or tty back into shape.
  1495. X */
  1496. Xbyetty()
  1497. X{
  1498. X}
  1499. X#endif
  1500. X
  1501. X/* read up to max chars into buf, with cannonization.
  1502. X * add trailing '\0' (buf is really max+1 chars long).
  1503. X * return count of chars read (not counting '\0').
  1504. X * assume cursor is already positioned as desired.
  1505. X * if type END when n==0 then return -1.
  1506. X */
  1507. Xread_line (buf, max)
  1508. Xchar buf[];
  1509. Xint max;
  1510. X{
  1511. X    static char erase[] = "\b \b";
  1512. X    int n, c;
  1513. X    int done;
  1514. X
  1515. X#ifdef UNIX
  1516. X    if (!ttysetup) setuptty();
  1517. X#endif
  1518. X
  1519. X    for (done = 0, n = 0; !done; )
  1520. X        switch (c = read_char()) {    /* does not echo */
  1521. X        case cntrl('h'):    /* backspace or */
  1522. X        case 0177:        /* delete are each char erase */
  1523. X        if (n > 0) {
  1524. X            fputs (erase, stdout);
  1525. X            n -= 1;
  1526. X        }
  1527. X        break;
  1528. X        case cntrl('u'):        /* line erase */
  1529. X        while (n > 0) {
  1530. X            fputs (erase, stdout);
  1531. X            n -= 1;
  1532. X        }
  1533. X        break;
  1534. X        case '\r':    /* EOL */
  1535. X        done++;
  1536. X        break;
  1537. X        default:            /* echo and store, if ok */
  1538. X        if (n == 0 && c == END)
  1539. X            return (-1);
  1540. X        if (n >= max)
  1541. X            putchar (cntrl('g'));
  1542. X        else if (c >= ' ') {
  1543. X            putchar (c);
  1544. X            buf[n++] = c;
  1545. X        }
  1546. X        }
  1547. X
  1548. X    buf[n] = '\0';
  1549. X    return (n);
  1550. X}
  1551. EOFxEOF
  1552. len=`wc -c < io.c`
  1553. if expr $len != 8533 > /dev/null
  1554. then echo Length of io.c is $len but it should be 8533.
  1555. fi
  1556. echo x main.c
  1557. sed -e 's/^X//' << 'EOFxEOF' > main.c
  1558. X/* main "ephem" program. 
  1559. X * -------------------------------------------------------------------
  1560. X * Copyright (c) 1990 by Elwood Charles Downey
  1561. X * 
  1562. X * Permission is granted to make and distribute copies of this program
  1563. X * free of charge, provided the copyright notice and this permission
  1564. X * notice are preserved on all copies.  All other rights reserved.
  1565. X * -------------------------------------------------------------------
  1566. X * set options.
  1567. X * init screen and circumstances.
  1568. X * enter infinite loop updating screen and allowing operator input.
  1569. X */
  1570. X
  1571. X#include <stdio.h>
  1572. X#include <signal.h>
  1573. X#include <math.h>
  1574. X#include "astro.h"
  1575. X#include "circum.h"
  1576. X#include "screen.h"
  1577. X
  1578. Xextern char *getenv();
  1579. Xextern char *strcpy();
  1580. X
  1581. X/* shorthands for fields of a Now structure, now.
  1582. X * first undo the ones for a Now pointer from circum.h.
  1583. X */
  1584. X#undef mjd
  1585. X#undef lat
  1586. X#undef lng
  1587. X#undef tz
  1588. X#undef temp
  1589. X#undef pressure
  1590. X#undef height
  1591. X#undef epoch
  1592. X#undef tznm
  1593. X
  1594. X#define mjd    now.n_mjd
  1595. X#define lat    now.n_lat
  1596. X#define lng    now.n_lng
  1597. X#define tz    now.n_tz
  1598. X#define temp    now.n_temp
  1599. X#define pressure now.n_pressure
  1600. X#define height    now.n_height
  1601. X#define epoch    now.n_epoch
  1602. X#define tznm    now.n_tznm
  1603. X
  1604. Xstatic char *cfgfile = "ephem.cfg";    /* default config filename */
  1605. X
  1606. Xstatic Now now;        /* where when and how, right now */
  1607. Xstatic double tminc;    /* hrs to inc time by each loop; RTC means use clock */
  1608. Xstatic int nstep;    /* steps to go before stopping */
  1609. Xstatic int optwi;    /* set when want to display dawn/dusk/len-of-night */
  1610. Xstatic int oppl;    /* mask of (1<<planet) bits; set when want to show it */
  1611. X
  1612. Xmain (ac, av)
  1613. Xint ac;
  1614. Xchar *av[];
  1615. X{
  1616. X    void bye();
  1617. X    static char freerun[] =
  1618. X        "Running... press any key to stop to make changes.";
  1619. X    static char prmpt[] =
  1620. X"Move to another field, RETURN to change this field, ? for help, or q to run";
  1621. X    static char hlp[] =
  1622. X    "arrow keys move to field; any key stops running; ^d exits; ^l redraws";
  1623. X    int curr = R_NSTEP, curc = C_NSTEPV;    /* must start somewhere */
  1624. X    int sflag = 0;    /* not silent, by default */
  1625. X    int one = 1;    /* use a variable so optimizer doesn't get disabled */
  1626. X    int srchdone = 0; /* true when search funcs say so */
  1627. X    int newcir = 2;    /* set when circumstances change - means don't tminc */
  1628. X
  1629. X    while ((--ac > 0) && (**++av == '-')) {
  1630. X        char *s;
  1631. X        for (s = *av+1; *s != '\0'; s++)
  1632. X        switch (*s) {
  1633. X        case 's': /* no credits "silent" (don't publish this) */
  1634. X            sflag++;
  1635. X            break;
  1636. X        case 'c': /* set name of config file to use */
  1637. X            if (--ac <= 0) usage("-c but no config file");
  1638. X            cfgfile = *++av;
  1639. X            break;
  1640. X        default:
  1641. X            usage("Bad - option");
  1642. X        }
  1643. X    }
  1644. X
  1645. X    if (!sflag)
  1646. X        credits();
  1647. X
  1648. X    /* fresh screen.
  1649. X     * crack config file, THEN args so args may override.
  1650. X     */
  1651. X    c_erase();
  1652. X    read_cfgfile (cfgfile);
  1653. X    read_fieldargs (ac, av);
  1654. X
  1655. X    /* set up to clean up screen and tty if interrupted */
  1656. X    signal (SIGINT, bye);
  1657. X
  1658. X    /* update screen forever (until QUIT) */
  1659. X    while (one) {
  1660. X
  1661. X        nstep -= 1;
  1662. X
  1663. X        /* recalculate everything and update all the fields */
  1664. X        redraw_screen (newcir);
  1665. X        mm_newcir (0);
  1666. X
  1667. X        /* let searching functions change tminc and check for done */
  1668. X        srchdone = srch_eval (mjd, &tminc) < 0;
  1669. X        print_tminc(0);    /* to show possibly new search increment */
  1670. X
  1671. X        /* update plot file, now that all fields are up to date and
  1672. X         * search function has been evaluated.
  1673. X         */
  1674. X        plot();
  1675. X
  1676. X        /* stop loop to allow op to change parameters:
  1677. X         * if a search evaluation converges (or errors out),
  1678. X         * or if steps are done,
  1679. X         * or if op hits any key.
  1680. X         */
  1681. X        newcir = 0;
  1682. X        if (srchdone || nstep <= 0 || (chk_char()==0 && read_char()!=0)) {
  1683. X        int fld;
  1684. X
  1685. X        /* update screen with the current stuff if stopped during
  1686. X         * unattended plotting since last redraw_screen() didn't.
  1687. X         */
  1688. X        if (plot_ison() && nstep > 0)
  1689. X            redraw_screen (1);
  1690. X
  1691. X        /* return nstep to default of 1 */
  1692. X        if (nstep <= 0) {
  1693. X            nstep = 1;
  1694. X            print_nstep (0);
  1695. X        }
  1696. X
  1697. X        /* change fields until END.
  1698. X         * update all time fields if any are changed
  1699. X         * and print NEW CIRCUMSTANCES if any have changed.
  1700. X         * QUIT causes bye() to be called and we never return.
  1701. X         */
  1702. X        while(fld = sel_fld(curr,curc,alt_menumask()|F_CHG,prmpt,hlp)) {
  1703. X            if (chg_fld ((char *)0, fld)) {
  1704. X            mm_now (&now, 1);
  1705. X            mm_newcir(1);
  1706. X            newcir = 1;
  1707. X            }
  1708. X            curr = unpackr (fld);
  1709. X            curc = unpackc (fld);
  1710. X        }
  1711. X        if (nstep > 1)
  1712. X            f_prompt (freerun);
  1713. X        }
  1714. X
  1715. X        /* increment time only if op didn't change cirumstances */
  1716. X        if (!newcir)
  1717. X        inc_mjd (&now, tminc);
  1718. X    }
  1719. X
  1720. X    return (0);
  1721. X}
  1722. X
  1723. X/* draw all the stuff on the screen, using the current menu.
  1724. X * if how_much == 0 then just update fields that need it;
  1725. X * if how_much == 1 then redraw all fields;
  1726. X * if how_much == 2 then erase the screen and redraw EVERYTHING.
  1727. X */
  1728. Xredraw_screen (how_much)
  1729. Xint how_much;
  1730. X{
  1731. X    if (how_much == 2)
  1732. X        c_erase();
  1733. X
  1734. X    /* print the single-step message if this is the last loop */
  1735. X    if (nstep < 1)
  1736. X        print_updating();
  1737. X
  1738. X    if (how_much == 2) {
  1739. X        mm_borders();
  1740. X        mm_labels();
  1741. X        srch_prstate(1);
  1742. X        plot_prstate(1);
  1743. X        alt_labels();
  1744. X    }
  1745. X
  1746. X    /* if just updating changed fields while plotting unattended then
  1747. X     * suppress most screen updates except
  1748. X     * always show nstep to show plot loops to go and
  1749. X     * always show tminc to show search convergence progress.
  1750. X     */
  1751. X    print_nstep(how_much);
  1752. X    print_tminc(how_much);
  1753. X    if (how_much == 0 && plot_ison() && nstep > 0)
  1754. X        f_off();
  1755. X
  1756. X    /* print all the time-related fields */
  1757. X    mm_now (&now, how_much);
  1758. X
  1759. X    if (optwi)
  1760. X        mm_twilight (&now, how_much);
  1761. X
  1762. X    /* print solar system body info */
  1763. X    print_bodies (how_much);
  1764. X
  1765. X    f_on();
  1766. X}
  1767. X
  1768. X/* clean up and exit for sure.
  1769. X */
  1770. Xvoid
  1771. Xbye()
  1772. X{
  1773. X    c_erase();
  1774. X    byetty();
  1775. X    exit (0);
  1776. X}
  1777. X
  1778. Xstatic
  1779. Xusage(why)
  1780. Xchar *why;
  1781. X{
  1782. X    /* don't advertise -s (silent) option */
  1783. X    c_erase();
  1784. X    f_string (1, 1, why);
  1785. X    f_string (2, 1, "usage: [-c <configfile>] [field=value] ...\r\n");
  1786. X    byetty();
  1787. X    exit (1);
  1788. X}
  1789. X
  1790. X/* read cfg file, fn, if present.
  1791. X * if errors in file, call usage() (which exits).
  1792. X * try $HOME/.ephemrc as last resort.
  1793. X * skip blank lines and lines that begin with '#', '*', ' ' or '\t'.
  1794. X */
  1795. Xstatic
  1796. Xread_cfgfile(fn)
  1797. Xchar *fn;
  1798. X{
  1799. X    char buf[128];
  1800. X    FILE *fp;
  1801. X
  1802. X    fp = fopen (fn, "r");
  1803. X    if (!fp) {
  1804. X        char *home = getenv ("HOME");
  1805. X        if (home) {
  1806. X        sprintf (buf, "%s/.ephemrc", home);
  1807. X        fp = fopen (buf, "r");
  1808. X        if (!fp)
  1809. X            return;    /* oh well */
  1810. X        fn = buf;    /* save fn for error report */
  1811. X        }
  1812. X    }
  1813. X
  1814. X    while (fgets (buf, sizeof(buf), fp)) {
  1815. X        switch (buf[0]) {
  1816. X        case '#': case '*': case ' ': case '\t': case '\n':
  1817. X        continue;
  1818. X        }
  1819. X        buf[strlen(buf)-1] = '\0';        /* discard trailing \n */
  1820. X        if (crack_fieldset (buf) < 0) {
  1821. X        char why[128];
  1822. X        sprintf (why, "Unknown field spec in %s: %s\n", fn, buf);
  1823. X        usage (why);
  1824. X        }
  1825. X    }
  1826. X    fclose (fp);
  1827. X}
  1828. X
  1829. X/* process the field specs from the command line.
  1830. X * if trouble call usage() (which exits).
  1831. X */
  1832. Xstatic
  1833. Xread_fieldargs (ac, av)
  1834. Xint ac;        /* number of such specs */
  1835. Xchar *av[];    /* array of strings in form <field_name value> */
  1836. X{
  1837. X    while (--ac >= 0) {
  1838. X        char *fs = *av++;
  1839. X        if (crack_fieldset (fs) < 0) {
  1840. X        char why[128];
  1841. X        sprintf (why, "Unknown command line field spec: %s", fs);
  1842. X        usage (why);
  1843. X        }
  1844. X    }
  1845. X}
  1846. X
  1847. X/* process a field spec in buf, either from config file or argv.
  1848. X * return 0 if recognized ok, else -1.
  1849. X */
  1850. Xstatic
  1851. Xcrack_fieldset (buf)
  1852. Xchar *buf;
  1853. X{
  1854. X    if (strncmp ("LAT", buf, 3) == 0)
  1855. X        (void) chg_fld (buf+4, rcfpack (R_LAT,C_LATV,0));
  1856. X    else if (strncmp ("LONG", buf, 4) == 0)
  1857. X        (void) chg_fld (buf+5, rcfpack (R_LONG,C_LONGV,0));
  1858. X    else if (strncmp ("UT", buf, 2) == 0)
  1859. X        (void) chg_fld (buf+3, rcfpack (R_UT,C_UTV,0));
  1860. X    else if (strncmp ("UD", buf, 2) == 0)
  1861. X        (void) chg_fld (buf+3, rcfpack (R_UD,C_UD,0));
  1862. X    else if (strncmp ("TZONE", buf, 5) == 0)
  1863. X        (void) chg_fld (buf+6, rcfpack (R_TZONE,C_TZONEV,0));
  1864. X    else if (strncmp ("TZNAME", buf, 6) == 0)
  1865. X        (void) chg_fld (buf+7, rcfpack (R_TZN,C_TZN,0));
  1866. X    else if (strncmp ("HEIGHT", buf, 6) == 0)
  1867. X        (void) chg_fld (buf+7, rcfpack (R_HEIGHT,C_HEIGHTV,0));
  1868. X    else if (strncmp ("NSTEP", buf, 5) == 0)
  1869. X        (void) chg_fld (buf+6, rcfpack (R_NSTEP,C_NSTEPV,0));
  1870. X    else if (strncmp ("STPSZ", buf, 5) == 0)
  1871. X        (void) chg_fld (buf+6, rcfpack (R_STPSZ,C_STPSZV,0));
  1872. X    else if (strncmp ("TEMP", buf, 4) == 0)
  1873. X        (void) chg_fld (buf+5, rcfpack (R_TEMP,C_TEMPV,0));
  1874. X    else if (strncmp ("PRES", buf, 4) == 0)
  1875. X        (void) chg_fld (buf+5, rcfpack (R_PRES,C_PRESV,0));
  1876. X    else if (strncmp ("EPOCH", buf, 5) == 0)
  1877. X        (void) chg_fld (buf+6, rcfpack (R_EPOCH,C_EPOCHV,0));
  1878. X    else if (strncmp ("JD", buf, 2) == 0)
  1879. X        (void) chg_fld (buf+3, rcfpack (R_JD,C_JDV,0));
  1880. X    else if (strncmp ("OBJX", buf, 4) == 0)
  1881. X        (void) objx_define (buf+5);
  1882. X    else if (strncmp ("PROPTS", buf, 6) == 0) {
  1883. X        char *bp = buf+7;
  1884. X        if (buf[6] != '+')
  1885. X        optwi = oppl = 0;
  1886. X        while (*bp)
  1887. X        switch (*bp++) {
  1888. X        case 'T': optwi = 1; break;
  1889. X        case 'S': oppl |= (1<<SUN); break;
  1890. X        case 'M': oppl |= (1<<MOON); break;
  1891. X        case 'e': oppl |= (1<<MERCURY); break;
  1892. X        case 'v': oppl |= (1<<VENUS); break;
  1893. X        case 'm': oppl |= (1<<MARS); break;
  1894. X        case 'j': oppl |= (1<<JUPITER); break;
  1895. X        case 's': oppl |= (1<<SATURN); break;
  1896. X        case 'u': oppl |= (1<<URANUS); break;
  1897. X        case 'n': oppl |= (1<<NEPTUNE); break;
  1898. X        case 'p': oppl |= (1<<PLUTO); break;
  1899. X        case 'x': oppl |= (1<<OBJX); objx_on(); break;
  1900. X        }
  1901. X    } else
  1902. X        return (-1);
  1903. X    return (0);
  1904. X}
  1905. X
  1906. X/* change the field at rcpk according to the optional string input at bp.
  1907. X * if bp is != 0 use it, else issue read_line() and use buffer.
  1908. X * then sscanf the buffer and update the corresponding (global) variable(s)
  1909. X * or do whatever a pick at that field should do.
  1910. X * return 1 if we change a field that invalidates any of the times or
  1911. X * to update all related fields.
  1912. X */
  1913. Xstatic
  1914. Xchg_fld (bp, rcpk)
  1915. Xchar *bp;
  1916. Xint rcpk;
  1917. X{
  1918. X    char buf[NC];
  1919. X    int deghrs = 0, mins = 0, secs = 0;
  1920. X    int new = 0;
  1921. X
  1922. X    /* switch on just the row/col portion */
  1923. X    switch (unpackrc(rcpk)) {
  1924. X    case rcfpack (R_ALTM, C_ALTM, 0):
  1925. X        if (altmenu_setup() == 0) {
  1926. X        print_updating();
  1927. X        alt_nolabels();
  1928. X        clrall_bodies();
  1929. X        alt_labels();
  1930. X        print_bodies(1);
  1931. X        }
  1932. X        break;
  1933. X    case rcfpack (R_JD, C_JDV, 0):
  1934. X        if (!bp) {
  1935. X        static char p[] = "Julian Date (or n for Now): ";
  1936. X        f_prompt (p);
  1937. X        if (read_line (buf, PW-sizeof(p)) <= 0)
  1938. X            break;
  1939. X        bp = buf;
  1940. X        }
  1941. X        if (bp[0] == 'n' || bp[0] == 'N')
  1942. X        time_fromsys (&now);
  1943. X        else
  1944. X        mjd = atof(bp) - 2415020L;
  1945. X        set_t0 (&now);
  1946. X        new = 1;
  1947. X        break;
  1948. X    case rcfpack (R_UD, C_UD, 0):
  1949. X        if (!bp) {
  1950. X        static char p[] = "utc date (m/d/y, or year.d, or n for Now): ";
  1951. X        f_prompt (p);
  1952. X        if (read_line (buf, PW-sizeof(p)) <= 0)
  1953. X            break;
  1954. X        bp = buf;
  1955. X        }
  1956. X        if (bp[0] == 'n' || bp[0] == 'N')
  1957. X        time_fromsys (&now);
  1958. X        else {
  1959. X        if (decimal_year(bp)) {
  1960. X            double y = atof (bp);
  1961. X            year_mjd (y, &mjd);
  1962. X        } else {
  1963. X            double day, newmjd0;
  1964. X            int month, year;
  1965. X            mjd_cal (mjd, &month, &day, &year); /* init with now */
  1966. X            f_sscandate (bp, &month, &day, &year);
  1967. X            cal_mjd (month, day, year, &newmjd0);
  1968. X            /* if don't give a fractional part to days
  1969. X             * then retain current hours.
  1970. X             */
  1971. X            if ((long)day == day)
  1972. X            mjd = newmjd0 + mjd_hr(mjd)/24.0;
  1973. X            else
  1974. X            mjd = newmjd0;
  1975. X        }
  1976. X        }
  1977. X        set_t0 (&now);
  1978. X        new = 1;
  1979. X        break;
  1980. X    case rcfpack (R_UT, C_UTV, 0):
  1981. X        if (!bp) {
  1982. X        static char p[] = "utc time (h:m:s, or n for Now): ";
  1983. X        f_prompt (p);
  1984. X        if (read_line (buf, PW-sizeof(p)) <= 0)
  1985. X            break;
  1986. X        bp = buf;
  1987. X        }
  1988. X        if (bp[0] == 'n' || bp[0] == 'N')
  1989. X        time_fromsys (&now);
  1990. X        else {
  1991. X        double newutc = (mjd-mjd_day(mjd)) * 24.0;
  1992. X        f_dec_sexsign (newutc, °hrs, &mins, &secs);
  1993. X        f_sscansex (bp, °hrs, &mins, &secs);
  1994. X        sex_dec (deghrs, mins, secs, &newutc);
  1995. X        mjd = mjd_day(mjd) + newutc/24.0;
  1996. X        }
  1997. X        set_t0 (&now);
  1998. X        new = 1;
  1999. X        break;
  2000. X    case rcfpack (R_LD, C_LD, 0):
  2001. X        if (!bp) {
  2002. X        static char p[] = "local date (m/d/y, or year.d, n for Now): ";
  2003. X        f_prompt (p);
  2004. X        if (read_line (buf, PW-sizeof(p)) <= 0)
  2005. X            break;
  2006. X        bp = buf;
  2007. X        }
  2008. X        if (bp[0] == 'n' || bp[0] == 'N')
  2009. X        time_fromsys (&now);
  2010. X        else {
  2011. X        if (decimal_year(bp)) {
  2012. X            double y = atof (bp);
  2013. X            year_mjd (y, &mjd);
  2014. X            mjd += tz/24.0;
  2015. X        } else {
  2016. X            double day, newlmjd0;
  2017. X            int month, year;
  2018. X            mjd_cal (mjd-tz/24.0, &month, &day, &year); /* now */
  2019. X            f_sscandate (bp, &month, &day, &year);
  2020. X            cal_mjd (month, day, year, &newlmjd0);
  2021. X            /* if don't give a fractional part to days
  2022. X             * then retain current hours.
  2023. X             */
  2024. X            if ((long)day == day)
  2025. X            mjd = newlmjd0 + mjd_hr(mjd-tz/24.0)/24.0;
  2026. X            else
  2027. X            mjd = newlmjd0;
  2028. X            mjd += tz/24.0;
  2029. X        }
  2030. X        }
  2031. X        set_t0 (&now);
  2032. X        new = 1;
  2033. X        break;
  2034. X    case rcfpack (R_LT, C_LT, 0):
  2035. X        if (!bp) {
  2036. X        static char p[] = "local time (h:m:s, or n for Now): ";
  2037. X        f_prompt (p);
  2038. X        if (read_line (buf, PW-sizeof(p)) <= 0)
  2039. X            break;
  2040. X        bp = buf;
  2041. X        }
  2042. X        if (bp[0] == 'n' || bp[0] == 'N')
  2043. X        time_fromsys (&now);
  2044. X        else {
  2045. X        double newlt = (mjd-mjd_day(mjd)) * 24.0 - tz;
  2046. X        range (&newlt, 24.0);
  2047. X        f_dec_sexsign (newlt, °hrs, &mins, &secs);
  2048. X        f_sscansex (bp, °hrs, &mins, &secs);
  2049. X        sex_dec (deghrs, mins, secs, &newlt);
  2050. X        mjd = mjd_day(mjd-tz/24.0) + (newlt + tz)/24.0;
  2051. X        }
  2052. X        set_t0 (&now);
  2053. X        new = 1;
  2054. X        break;
  2055. X    case rcfpack (R_LST, C_LSTV, 0):
  2056. X        if (!bp) {
  2057. X        static char p[] = "local sidereal time (h:m:s, or n for Now): ";
  2058. X        f_prompt (p);
  2059. X        if (read_line (buf, PW-sizeof(p)) <= 0)
  2060. X            break;
  2061. X        bp = buf;
  2062. X        }
  2063. X        if (bp[0] == 'n' || bp[0] == 'N')
  2064. X        time_fromsys (&now);
  2065. X        else {
  2066. X        double lst, utc;
  2067. X        now_lst (&now, &lst);
  2068. X        f_dec_sexsign (lst, °hrs, &mins, &secs);
  2069. X        f_sscansex (bp, °hrs, &mins, &secs);
  2070. X        sex_dec (deghrs, mins, secs, &lst);
  2071. X        lst -= radhr(lng); /* convert to gst */
  2072. X        range (&lst, 24.0);
  2073. X        gst_utc (mjd_day(mjd), lst, &utc);
  2074. X        mjd = mjd_day(mjd) + utc/24.0;
  2075. X        }
  2076. X        set_t0 (&now);
  2077. X        new = 1;
  2078. X        break;
  2079. X    case rcfpack (R_TZN, C_TZN, 0):
  2080. X        if (!bp) {
  2081. X        static char p[] = "timezone abbreviation (3 char max): ";
  2082. X        f_prompt (p);
  2083. X        if (read_line (buf, 3) <= 0)
  2084. X            break;
  2085. X        bp = buf;
  2086. X        }
  2087. X        strcpy (tznm, bp);
  2088. X        new = 1;
  2089. X        break;
  2090. X    case rcfpack (R_TZONE, C_TZONEV, 0):
  2091. X        if (!bp) {
  2092. X        static char p[] = "hours behind utc: ";
  2093. X        f_prompt (p);
  2094. X        if (read_line (buf, PW-sizeof(p)) <= 0)
  2095. X            break;
  2096. X        bp = buf;
  2097. X        }
  2098. X        f_dec_sexsign (tz, °hrs, &mins, &secs);
  2099. X        f_sscansex (bp, °hrs, &mins, &secs);
  2100. X        sex_dec (deghrs, mins, secs, &tz);
  2101. X        new = 1;
  2102. X        break;
  2103. X    case rcfpack (R_LONG, C_LONGV, 0):
  2104. X        if (!bp) {
  2105. X        static char p[] = "longitude (+ west) (d:m:s): ";
  2106. X        f_prompt (p);
  2107. X        if (read_line (buf, PW-sizeof(p)) <= 0)
  2108. X            break;
  2109. X        bp = buf;
  2110. X        }
  2111. X        f_dec_sexsign (-raddeg(lng), °hrs, &mins, &secs);
  2112. X        f_sscansex (bp, °hrs, &mins, &secs);
  2113. X        sex_dec (deghrs, mins, secs, &lng);
  2114. X        lng = degrad (-lng);         /* want - radians west */
  2115. X        new = 1;
  2116. X        break;
  2117. X    case rcfpack (R_LAT, C_LATV, 0):
  2118. X        if (!bp) {
  2119. X        static char p[] = "latitude (+ north) (d:m:s): ";
  2120. X        f_prompt (p);
  2121. X        if (read_line (buf, PW-sizeof(p)) <= 0)
  2122. X            break;
  2123. X        bp = buf;
  2124. X        }
  2125. X        f_dec_sexsign (raddeg(lat), °hrs, &mins, &secs);
  2126. X        f_sscansex (bp, °hrs, &mins, &secs);
  2127. X        sex_dec (deghrs, mins, secs, &lat);
  2128. X        lat = degrad (lat);
  2129. X        new = 1;
  2130. X        break;
  2131. X    case rcfpack (R_HEIGHT, C_HEIGHTV, 0):
  2132. X        if (!bp) {
  2133. X        static char p[] = "height above sea level (ft): ";
  2134. X        f_prompt (p);
  2135. X        if (read_line (buf, PW-sizeof(p)) <= 0)
  2136. X            break;
  2137. X        bp = buf;
  2138. X        }
  2139. X        sscanf (bp, "%lf", &height);
  2140. X        height /= 2.093e7; /* convert ft to earth radii above sea level */
  2141. X        new = 1;
  2142. X        break;
  2143. X    case rcfpack (R_NSTEP, C_NSTEPV, 0):
  2144. X        if (!bp) {
  2145. X        static char p[] = "number of steps to run: ";
  2146. X        f_prompt (p);
  2147. X        if (read_line (buf, 8) <= 0)
  2148. X            break;
  2149. X        bp = buf;
  2150. X        }
  2151. X        sscanf (bp, "%d", &nstep);
  2152. X        print_nstep (0);
  2153. X        break;
  2154. X    case rcfpack (R_TEMP, C_TEMPV, 0):
  2155. X        if (!bp) {
  2156. X        static char p[] = "temperature (deg.F): ";
  2157. X        f_prompt (p);
  2158. X        if (read_line (buf, PW-sizeof(p)) <= 0)
  2159. X            break;
  2160. X        bp = buf;
  2161. X        }
  2162. X        sscanf (bp, "%lf", &temp);
  2163. X        temp = 5./9.*(temp - 32.0);    /* want degs C */
  2164. X        new = 1;
  2165. X        break;
  2166. X    case rcfpack (R_PRES, C_PRESV, 0):
  2167. X        if (!bp) {
  2168. X        static char p[] =
  2169. X            "atmos pressure (in. Hg; 0 for no refraction correction): ";
  2170. X        f_prompt (p);
  2171. X        if (read_line (buf, PW-sizeof(p)) <= 0)
  2172. X            break;
  2173. X        bp = buf;
  2174. X        }
  2175. X        sscanf (bp, "%lf", &pressure);
  2176. X        pressure *= 33.86;        /* want mBar */
  2177. X        new = 1;
  2178. X        break;
  2179. X    case rcfpack (R_EPOCH, C_EPOCHV, 0):
  2180. X        if (!bp) {
  2181. X        static char p[] = "epoch (year, or e for Equinox of Date): ";
  2182. X        f_prompt (p);
  2183. X        if (read_line (buf, PW-strlen(p)) <= 0)
  2184. X            break;
  2185. X        bp = buf;
  2186. X        }
  2187. X        if (bp[0] == 'e' || bp[0] == 'E')
  2188. X        epoch = EOD;
  2189. X        else {
  2190. X        double e;
  2191. X        e = atof(bp);
  2192. X        year_mjd (e, &epoch);
  2193. X        }
  2194. X        new = 1;
  2195. X        break;
  2196. X    case rcfpack (R_STPSZ, C_STPSZV, 0):
  2197. X        if (!bp) {
  2198. X        static char p[] =
  2199. X            "step size increment (h:m:s, or <x>d for x days, or r for RTC): ";
  2200. X        f_prompt (p);
  2201. X        if (read_line (buf, PW-sizeof(p)) <= 0)
  2202. X            break;
  2203. X        bp = buf;
  2204. X        }
  2205. X        if (bp[0] == 'r' || bp[0] == 'R')
  2206. X        tminc = RTC;
  2207. X        else {
  2208. X        int last = strlen (bp) - 1;
  2209. X        if (bp[last] == 'd') {
  2210. X            /* ends in d so treat as a number of days */
  2211. X            double x;
  2212. X            sscanf (bp, "%lf", &x);
  2213. X            tminc = x * 24.0;
  2214. X        } else {
  2215. X            if (tminc == RTC)
  2216. X            deghrs = mins = secs = 0;
  2217. X            else
  2218. X            f_dec_sexsign (tminc, °hrs, &mins, &secs);
  2219. X            f_sscansex (bp, °hrs, &mins, &secs);
  2220. X            sex_dec (deghrs, mins, secs, &tminc);
  2221. X        }
  2222. X        }
  2223. X        print_tminc(0);
  2224. X        set_t0 (&now);
  2225. X        break;
  2226. X    case rcfpack (R_PLOT, C_PLOT, 0):
  2227. X        plot_setup();
  2228. X        if (plot_ison())
  2229. X        new = 1;
  2230. X        break;
  2231. X    case rcfpack (R_WATCH, C_WATCH, 0):
  2232. X        watch (&now, tminc, oppl);
  2233. X        /* set new reference time to what watch left it.
  2234. X         * no need to set new since watch just did a redraw.
  2235. X         */
  2236. X        set_t0 (&now);
  2237. X        break;
  2238. X    case rcfpack (R_DAWN, C_DAWN, 0):
  2239. X    case rcfpack (R_DUSK, C_DUSK, 0):
  2240. X    case rcfpack (R_LON, C_LON, 0):
  2241. X        if (optwi ^= 1) {
  2242. X        print_updating();
  2243. X        mm_twilight (&now, 1);
  2244. X        } else {
  2245. X        f_blanks (R_DAWN, C_DAWNV, 5);
  2246. X        f_blanks (R_DUSK, C_DUSKV, 5);
  2247. X        f_blanks (R_LON, C_LONV, 5);
  2248. X        }
  2249. X        break;
  2250. X    case rcfpack (R_SRCH, C_SRCH, 0):
  2251. X        srch_setup();
  2252. X        if (srch_ison())
  2253. X        new = 1;
  2254. X        break;
  2255. X    case rcfpack (R_SUN, C_OBJ, 0):
  2256. X        if ((oppl ^= (1<<SUN)) & (1<<SUN)) {
  2257. X        print_updating();
  2258. X        alt_body (SUN, 1, &now);
  2259. X        } else
  2260. X        alt_nobody (SUN);
  2261. X        break;
  2262. X    case rcfpack (R_MOON, C_OBJ, 0):
  2263. X        if ((oppl ^= (1<<MOON)) & (1<<MOON)) {
  2264. X        print_updating();
  2265. X        alt_body (MOON, 1, &now);
  2266. X        } else
  2267. X        alt_nobody (MOON);
  2268. X        break;
  2269. X    case rcfpack (R_MERCURY, C_OBJ, 0):
  2270. X        if ((oppl ^= (1<<MERCURY)) & (1<<MERCURY)) {
  2271. X        print_updating();
  2272. X        alt_body (MERCURY, 1, &now);
  2273. X        } else
  2274. X        alt_nobody (MERCURY);
  2275. X        break;
  2276. X    case rcfpack (R_VENUS, C_OBJ, 0):
  2277. X        if ((oppl ^= (1<<VENUS)) & (1<<VENUS)) {
  2278. X        print_updating();
  2279. X        alt_body (VENUS, 1, &now);
  2280. X        } else
  2281. X        alt_nobody (VENUS);
  2282. X        break;
  2283. X    case rcfpack (R_MARS, C_OBJ, 0):
  2284. X        if ((oppl ^= (1<<MARS)) & (1<<MARS)) {
  2285. X        print_updating();
  2286. X        alt_body (MARS, 1, &now);
  2287. X        } else
  2288. X        alt_nobody (MARS);
  2289. X        break;
  2290. X    case rcfpack (R_JUPITER, C_OBJ, 0):
  2291. X        if ((oppl ^= (1<<JUPITER)) & (1<<JUPITER)) {
  2292. X        print_updating();
  2293. X        alt_body (JUPITER, 1, &now);
  2294. X        } else
  2295. X        alt_nobody (JUPITER);
  2296. X        break;
  2297. X    case rcfpack (R_SATURN, C_OBJ, 0):
  2298. X        if ((oppl ^= (1<<SATURN)) & (1<<SATURN)) {
  2299. X        print_updating();
  2300. X        alt_body (SATURN, 1, &now);
  2301. X        } else
  2302. X        alt_nobody (SATURN);
  2303. X        break;
  2304. X    case rcfpack (R_URANUS, C_OBJ, 0):
  2305. X        if ((oppl ^= (1<<URANUS)) & (1<<URANUS)) {
  2306. X        print_updating();
  2307. X        alt_body (URANUS, 1, &now);
  2308. X        } else
  2309. X        alt_nobody (URANUS);
  2310. X        break;
  2311. X    case rcfpack (R_NEPTUNE, C_OBJ, 0):
  2312. X        if ((oppl ^= (1<<NEPTUNE)) & (1<<NEPTUNE)) {
  2313. X        print_updating();
  2314. X        alt_body (NEPTUNE, 1, &now);
  2315. X        } else
  2316. X        alt_nobody (NEPTUNE);
  2317. X        break;
  2318. X    case rcfpack (R_PLUTO, C_OBJ, 0):
  2319. X        if ((oppl ^= (1<<PLUTO)) & (1<<PLUTO)) {
  2320. X        print_updating();
  2321. X        alt_body (PLUTO, 1, &now);
  2322. X        } else
  2323. X        alt_nobody (PLUTO);
  2324. X        break;
  2325. X    case rcfpack (R_OBJX, C_OBJ, 0):
  2326. X        /* this might change which columns are used so erase all when
  2327. X         * returns and redraw if still on.
  2328. X         */
  2329. X        objx_setup ();
  2330. X        alt_nobody (OBJX);
  2331. X        if (objx_ison()) {
  2332. X        oppl |= 1 << OBJX;
  2333. X        print_updating();
  2334. X        alt_body (OBJX, 1, &now);
  2335. X        } else
  2336. X        oppl &= ~(1 << OBJX);    /* already erased; just clear flag */
  2337. X        break;
  2338. X    }
  2339. X
  2340. X    return (new);
  2341. X}
  2342. X
  2343. Xstatic
  2344. Xprint_tminc(force)
  2345. Xint force;
  2346. X{
  2347. X    static double last;
  2348. X
  2349. X    if (force || tminc != last) {
  2350. X        if (tminc == RTC)
  2351. X        f_string (R_STPSZ, C_STPSZV, " RT CLOCK");
  2352. X        else if (fabs(tminc) >= 24.0)
  2353. X        f_double (R_STPSZ, C_STPSZV, "%6.4g dy", tminc/24.0);
  2354. X        else
  2355. X        f_signtime (R_STPSZ, C_STPSZV, tminc);
  2356. X        last = tminc;
  2357. X    }
  2358. X}
  2359. X
  2360. Xstatic
  2361. Xprint_bodies (force)
  2362. Xint force;
  2363. X{
  2364. X    int p;
  2365. X
  2366. X    for (p = nxtbody(-1); p != -1; p = nxtbody(p))
  2367. X        if (oppl & (1<<p))
  2368. X        alt_body (p, force, &now);
  2369. X}
  2370. X
  2371. Xstatic
  2372. Xclrall_bodies ()
  2373. X{
  2374. X    int p;
  2375. X
  2376. X    for (p = nxtbody(-1); p != -1; p = nxtbody(p))
  2377. X        if (oppl & (1<<p))
  2378. X        alt_nobody (p);
  2379. X}
  2380. X
  2381. Xprint_updating()
  2382. X{
  2383. X    f_prompt ("Updating...");
  2384. X}
  2385. X
  2386. Xstatic
  2387. Xprint_nstep(force)
  2388. Xint force;
  2389. X{
  2390. X    static int last;
  2391. X
  2392. X    if (force || nstep != last) {
  2393. X        char buf[16];
  2394. X        sprintf (buf, "%8d", nstep);
  2395. X        f_string (R_NSTEP, C_NSTEPV, buf);
  2396. X        last = nstep;
  2397. X    }
  2398. X}
  2399. EOFxEOF
  2400. len=`wc -c < main.c`
  2401. if expr $len != 21224 > /dev/null
  2402. then echo Length of main.c is $len but it should be 21224.
  2403. fi
  2404.  
  2405.